package com.computer.fundamentals.designpattern;

/**
 * 单例模式：双重校验锁（DCL，double checked locking）
 *
 * 优点：线程安全，且拥有高性能
 * 缺点：实现复杂
 * 使用场景：Spring中的Singleton
 */
public class DoubleCheckedLockingTest {

    // 加volatile关键字是为了增加内存屏障避免重排序，保证指令的有序性
    // 对象创建过程主要分为三步：1.分配内存空间；2.初始化对象；3.将对象指向刚分配的内存空间
    // 若存在重排序，可能会使2、3两步对调执行，而这就有可能让其他线程访问了一个未完全初始化的对象，因此必须禁止重排序
    public volatile static DoubleCheckedLockingTest instance;

    // 通过这种私有化构造器的方式可以防止外部获取接口
    private DoubleCheckedLockingTest(){}

    /**
     * 获取实例
     */
    public static DoubleCheckedLockingTest getInstance() {
        // 若已创建实例则直接返回
        if (instance == null) {
            // 加锁保证创建实例过程的线程安全
            synchronized (DoubleCheckedLockingTest.class) {
                // 若不进行判空，拿到锁后直接创建实例可能会存在以下情况
                // 多个线程同时通过了第一次检查，但只要有一个线程成功创建，其他线程再创建就违背了单例的原则
                if (instance == null) {
                    instance = new DoubleCheckedLockingTest();
                }
            }
        }

        return instance;
    }

    /**
     * 测试
     */
    public static void main(String[] args) {

        System.out.println(getInstance());

    }
}